/*
   Copyright 2011-2012 gtalent2@gmail.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
package world

import (
	"runtime"
	"sync"
	"sync/atomic"
)

type pauseManager struct {
	paused  bool
	pausing int32
	cond    *sync.Cond
}

func newPauseManager() pauseManager {
	var pm pauseManager
	pm.cond = sync.NewCond(new(sync.Mutex))
	return pm
}

func (me *pauseManager) pause() {
	// in the unlikely case that the World is repaused while
	// before all threads get through the current pause,
	// wait until the current pause is over
	for me.pausing > 0 {
		runtime.Gosched()
	}
	me.paused = true
}

func (me *pauseManager) unpause() {
	me.cond.L.Lock()
	me.paused = false
	me.cond.L.Unlock()
	me.cond.Broadcast()
}

//Waits if the World is paused.
func (me *pauseManager) wait() {
	//don't bother locking if not paused,
	//it's okay if some threads get through right after the pausing
	if !me.paused {
		return
	}
	atomic.AddInt32(&me.pausing, 1)
	me.cond.L.Lock()
	//yes, I meant to use an "if" here
	if me.paused {
		me.cond.Wait()
	}
	me.cond.L.Unlock()
	atomic.AddInt32(&me.pausing, -1)
}
